import AMapLoader from '@amap/amap-jsapi-loader'
import '@amap/amap-jsapi-types'
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'

import alerClusterPng20 from '@/assets/icons/safeCoGovernance/alerCluster20.png'
import alerClusterPng28 from '@/assets/icons/safeCoGovernance/alerCluster28.png'
import alerClusterPng39 from '@/assets/icons/safeCoGovernance/alerCluster39.png'
import alerMakerPng from '@/assets/icons/safeCoGovernance/alerMaker.png'
import { provinceCityDistrictObj } from '@/constant/provinceCityDistrictObj'
import { splicePlateNum } from '@/utils/compUtils'

import type { AssociationData } from '../../../BigScreenBase/interface'
import type { WarnGpsDetail } from '../../data'
import { getMapAlerData } from '../../data'
import type { IAlerGeoData, SwitchAndIntervalRef } from '../../interface'
import { renderMakerItemDom } from '../../utils'

// initial/switchXiehui/switchMapShowType:点聚合图层 AlerDisClusterRef.current === undefiend,  initial/switchXiehui/interval5才请求接口
type AlerRequestType =
  | 'initial'
  | 'zoom'
  | 'interval5'
  | 'switchMapShowType'
  | 'switchXiehui'
interface AlerMapProps {
  selectedAssociationItem: AssociationData
  onInitialWeatherPlugin: (weatherPlugin: any) => void
  onStartTimer: () => void
  onClearTimer: () => void
}

type TMapShowType = 'heat' | 'poi'
export interface AlerMapRef extends SwitchAndIntervalRef {
  switchAlerMapShowType: (newAlerMapShowType: TMapShowType) => void
}
interface WarnGpsDetailRender
  extends Omit<WarnGpsDetail, 'longitude' | 'latitude'> {
  count: number
  lnglat: [number, number]
}

const AlerMap = forwardRef<AlerMapRef, AlerMapProps>((props, ref) => {
  const {
    onInitialWeatherPlugin,
    selectedAssociationItem: { key, regionCode },
    onClearTimer,
    onStartTimer
  } = props

  const AMapRef = useRef<any>()
  const LocaRef = useRef<any>()
  const alerDataListRef = useRef<WarnGpsDetailRender[]>([])
  const mapShowTypeRef = useRef<TMapShowType>('heat')
  const HeatMapRef = useRef<any>() //热力图
  const AlerPointLayerRef = useRef<any>() //数据可视化图层  [5,12]
  const AlerDisClusterRef = useRef<any>() //点聚合 [12,14]
  const AlerMassMarkersRef = useRef<any>() //海量点 [14,21]
  const prevZoomRef = useRef<number>(0)

  const AlerInfoWindowRef = useRef<any>() //点击还两点的信息窗口

  //设置地图中心
  function _setMapCenter(regionCode: string | undefined) {
    if (regionCode) {
      const centerStr = (provinceCityDistrictObj[regionCode] ?? {}).center
      if (centerStr) {
        const center = centerStr.split(',')
        const centerLnglat = new AMap.LngLat(
          Number(center[0]),
          Number(center[1])
        )
        AMapRef.current.setCenter(centerLnglat)
      }
    }
  }

  //可视化图层
  function _renderAlerPointLayer(alerDataList: WarnGpsDetailRender[]) {
    // 创建数据源
    const features: IAlerGeoData['features'] = alerDataList.map((listItem) => {
      const { lnglat, plateNumber } = listItem
      return {
        type: 'Feature',
        properties: {
          plateNumber
        },
        geometry: {
          type: 'Point',
          coordinates: lnglat
        }
      }
    })
    const mapAlerPointLayerData: IAlerGeoData = {
      type: 'FeatureCollection',
      features
    }
    const geo = new window.Loca.GeoJSONSource({
      data: mapAlerPointLayerData
    })

    if (!AlerPointLayerRef.current) {
      //创建点图层
      const pl = new window.Loca.PointLayer({
        zooms: [5, 12], //图层缩放等级范围
        zIndex: 10,
        blend: 'normal' //lighter
      })

      const style = {
        radius: 2.0,
        color: '#F55650',
        borderWidth: 0,
        // borderColor: "#56E3FF",
        blurWidth: -1, //模糊半径，从哪个位置开始向边缘模糊。负数代表不进行模糊。
        unit: 'px'
        // opacity: 0.2  //没起作用
      }
      //1.必须要在pl.addAnimate({...})的前面设置一次数据源，不然会pl.addAnimate()时会报错
      pl.setSource(new window.Loca.GeoJSONSource({ data: {} }))
      //设置点样式
      pl.setStyle(style)
      pl.addAnimate({
        key: 'radius',
        value: [0, 1], // 动画时长，单位毫秒
        duration: 500,
        easing: 'Linear',
        random: true, // 是否开启随机执行动画
        delay: 8000, // 随机动画延迟的时间段
        transform: 2000, // 随机动画的动画执行时间
        yoyo: true,
        repeat: 100000
      })
      //2.为了兼容：不让图层先从有到无(多了这一步)，在执行随机动画
      setTimeout(() => {
        //添加数据源
        pl.setSource(geo)
      }, 500)

      //添加图层
      LocaRef.current.add(pl)
      AlerPointLayerRef.current = pl
    } else {
      AlerPointLayerRef.current.setSource(geo)
    }
  }

  //点聚合
  function _renderAlerClusterMarker(context: any) {
    const { marker, count } = context
    let clusterPointDom
    if (count < 50) {
      clusterPointDom = renderMakerItemDom(count, alerClusterPng20, 20)
    } else if (count >= 50 && count < 150) {
      clusterPointDom = renderMakerItemDom(count, alerClusterPng28, 28)
    } else {
      clusterPointDom = renderMakerItemDom(count, alerClusterPng39, 39)
    }
    marker.setAnchor('center')
    marker.setzIndex(12)
    marker.setCursor('pointer')
    marker.setContent(clusterPointDom)
    marker.on('click', (e: any) => {
      let curZoom = AMapRef.current.getZoom()
      if (curZoom < 14) {
        curZoom += 1
      }
      AMapRef.current.setZoomAndCenter(curZoom, e.lnglat)
    })
  }

  function _renderAlerMarker(context: any) {
    const { data, marker, count } = context
    const currSize: any = [12, 16]
    const iconInstance = new AMap.Icon({
      size: currSize,
      image: alerMakerPng,
      imageSize: currSize
    })
    marker.setAnchor('center')
    marker.setIcon(iconInstance)
    marker.setzIndex(11)
    marker.setCursor('default')
  }

  //[12,14] 点聚合
  function _renderAlerClusterMaker(
    alerDataList: WarnGpsDetailRender[],
    requestType: AlerRequestType
  ) {
    const currZoom = AMapRef.current.getZoom()

    if (currZoom < 12 || currZoom >= 14) {
      prevZoomRef.current = currZoom
    }

    if (currZoom >= 12 && currZoom < 14) {
      if (!AlerDisClusterRef.current) {
        //requestType:'initial' / 'switchMapShowType' / 'switchXiehui'
        prevZoomRef.current = currZoom
        AlerDisClusterRef.current = new (AMap as any).MarkerCluster(
          AMapRef.current,
          alerDataList,
          {
            gridSize: 50, //数据聚合计算时网格的像素大小 默认60
            maxZoom: 14,
            renderClusterMarker: _renderAlerClusterMarker,
            renderMarker: _renderAlerMarker
          }
        )
      } else if (
        (requestType === 'zoom' &&
          (prevZoomRef.current < 12 || prevZoomRef.current >= 14)) || //滑出去再滑回来
        requestType === 'interval5'
      ) {
        prevZoomRef.current = currZoom
        AlerDisClusterRef.current.setData(alerDataList)
      }
    } else if (AlerDisClusterRef.current) {
      AlerDisClusterRef.current.setData([])
      // AlerDisClusterRef.current.setMap(null) //清除点聚合图层,清除完之后再进来setMap(AMapRef.current) 会导致无法按照距离点聚合了
    }

    // if (currZoom >= 14 && currZoom < 21) {
    //   prevZoomRef.current = currZoom;

    // }
  }

  //海量点
  function _renderAlerMissLayer(alerDataList: any[]) {
    if (!AlerMassMarkersRef.current) {
      AlerMassMarkersRef.current = new AMap.MassMarks(alerDataList, {
        zIndex: 200, //防止被地图字挡住
        cursor: 'point',
        // zooms: [14, 21],
        style: {
          url: alerMakerPng,
          anchor: new AMap.Pixel(6, 16),
          size: new AMap.Size(12, 16)
        } as any
      })
      AlerMassMarkersRef.current.setMap(AMapRef.current)
      AlerMassMarkersRef.current.setZooms([14, 21])
      AlerMassMarkersRef.current.on('click', (e: any) => {
        // console.log('--e.data--:', e.data);
        _alerMissMarkerClick(e.data)
      })
    } else {
      AlerMassMarkersRef.current.setData(alerDataList)
    }
  }

  //点击海量点
  function _alerMissMarkerClick(data: any) {
    const { lnglat, plateNumber } = data
    const windowInfoContent =
      '<span style="padding:4px 8px;border-radius: 2px;border: 1px solid;font-size: 14px;color: #FFFFFF;' +
      'background: linear-gradient( 180deg, rgba(0,0,0,0.16) 0%, rgba(0,0,0,0.32) 100%), linear-gradient( 180deg, rgba(246,110,44,0.04) 0%, rgba(0,0,0,0) 100%);' +
      'border-image: linear-gradient(180deg, rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.12)) 1 1;backdrop-filter: blur(8px);">' +
      splicePlateNum(plateNumber) +
      '</span>'
    if (!AlerInfoWindowRef.current) {
      AlerInfoWindowRef.current = new AMap.InfoWindow({
        anchor: 'middle-left',
        isCustom: true,
        content: windowInfoContent,
        offset: new AMap.Pixel(10, -10)
      })
    } else {
      AlerInfoWindowRef.current.setContent(windowInfoContent)
    }
    AlerInfoWindowRef.current.open(AMapRef.current, lnglat)
  }

  //热力图
  function _renderAlerHeathLayer(alerDataList: WarnGpsDetailRender[]) {
    if (!HeatMapRef.current) {
      HeatMapRef.current = new (AMap as any).HeatMap(AMapRef.current, {
        radius: 10, //热力图中单个点的半径 默认30
        opacity: [0, 0.72], //热力图透明度区间数组，取值范围 [0,1]
        zIndex: 130, //默认 130
        gradient: {
          0.2: '#3B9DFF',
          0.4: '#2BC1D7',
          0.6: '#66CCAE',
          0.75: '#14CC53',
          0.9: '#FFB13B',
          1.0: '#ee1212'
        }
      })
    }
    HeatMapRef.current!.setDataSet({
      data: alerDataList,
      max: 5 //其中max( 权重的最大值)不填则取数据集count最大值
    })
  }

  function _clearMapData() {
    //可视化图层
    if (AlerPointLayerRef.current) {
      AlerPointLayerRef.current.destroy()
      AlerPointLayerRef.current = undefined
    }

    //点聚合
    if (AlerDisClusterRef.current) {
      AlerDisClusterRef.current.setData([])
      AlerDisClusterRef.current.setMap(null)
      AlerDisClusterRef.current = undefined
    }

    //海量点
    if (AlerMassMarkersRef.current) {
      AlerMassMarkersRef.current.clear()
      AlerMassMarkersRef.current = undefined
    }

    //热力图
    if (HeatMapRef.current) {
      HeatMapRef.current.setDataSet({ max: 20, data: [] })
      HeatMapRef.current.setMap(null)
      HeatMapRef.current = undefined
    }
  }

  //地图基础数据
  function _getMapAlerData(entIdParam: string, requestType: AlerRequestType) {
    onClearTimer()
    _clearMapData()
    getMapAlerData({ entId: entIdParam })
      .then((res) => {
        const { data = [] } = res
        const newData: WarnGpsDetailRender[] = data
          .filter(
            (dataItem) =>
              typeof dataItem.longitude === 'number' &&
              typeof dataItem.latitude === 'number' &&
              dataItem.plateNumber
          )
          .map((dataItem) => {
            const { lng, lat, plateNumber, address, longitude, latitude } =
              dataItem
            return {
              lng: longitude, //可视化图层coordinates:lnglat， 点聚合lnglat， 海量点lnglat，热力图：lng，lat
              lat: latitude,
              plateNumber,
              address,
              lnglat: [longitude, latitude],
              count: 1
            }
          })
        alerDataListRef.current = newData
        if (mapShowTypeRef.current === 'heat') {
          //热力图
          _renderAlerHeathLayer(newData)
        } else {
          //[5,12] 可视化图层
          _renderAlerPointLayer(newData)

          //[12,14] 点聚合
          _renderAlerClusterMaker(newData, requestType)

          //[14,21] 海量点
          _renderAlerMissLayer(newData)
        }
        onStartTimer()
      })
      .catch((err) => {
        console.error('--AlerMap--getMapAlerData--err--:', err)
        onClearTimer()
        _clearMapData()
      })
  }

  //切换热力图/poi
  function _switchHeathOrPoi(newAlerMapShowType: TMapShowType) {
    if (newAlerMapShowType === 'heat') {
      //从poi到热力图
      //可视化图层
      AlerPointLayerRef.current.hide()

      //点聚合
      if (AlerDisClusterRef.current) {
        AlerDisClusterRef.current.setData([])
        AlerDisClusterRef.current.setMap(null)
        AlerDisClusterRef.current = undefined
      }
      //海量点
      AlerMassMarkersRef.current.hide()

      //热力图
      if (!HeatMapRef.current) {
        _renderAlerHeathLayer(alerDataListRef.current)
      } else {
        HeatMapRef.current.show()
      }
    } else {
      //从热力图到poi
      //热力图
      HeatMapRef.current.hide()

      //可视化图层
      if (!AlerPointLayerRef.current) {
        _renderAlerPointLayer(alerDataListRef.current)
      } else {
        AlerPointLayerRef.current.show()
      }

      //点聚合 (AlerDisClusterRef.current肯定不存在)
      _renderAlerClusterMaker(alerDataListRef.current, 'switchMapShowType')

      //海量点
      if (!AlerMassMarkersRef.current) {
        _renderAlerMissLayer(alerDataListRef.current)
      } else {
        AlerMassMarkersRef.current.show()
      }
    }
  }

  useImperativeHandle(ref, () => ({
    switchAlerMapShowType: (newAlerMapShowType) => {
      if (mapShowTypeRef.current === newAlerMapShowType) return
      // console.log("--切换--newAlerMapShowType--:", newAlerMapShowType)
      mapShowTypeRef.current = newAlerMapShowType
      _switchHeathOrPoi(newAlerMapShowType)
    },
    switchAssociation: (newAssociationId) => {
      _getMapAlerData(newAssociationId, 'switchXiehui')
    },
    intervalRefresh: () => {
      _getMapAlerData(key, 'interval5')
    },
    resize: () => {
      if (AMapRef.current) {
        AMapRef.current.resize()
      }
    }
  }))

  useEffect(() => {
    AMapLoader.load({
      key: import.meta.env.VITE_AMAP_APPKEY,
      version: '2.0',
      plugins: [
        'AMap.Weather',
        'AMap.MarkerCluster',
        'AMap.MassMarks',
        'AMap.HeatMap'
      ],
      Loca: {
        //LOCAL数据可视化 是否加载 Loca， 缺省不加载
        version: '2.0.0' // Loca 版本，缺省 1.3.2
      }
    }).then((AMap) => {
      onInitialWeatherPlugin(new AMap.Weather()) // 天气
      const mapOptions: AMap.MapOptions = {
        // center: [120.699279, 27.993849], //温州
        zoom: 10, //, //[3,20]
        zooms: [5, 20], //中国地图，
        viewMode: '2D', //设置地图模式
        mapStyle: 'amap://styles/grey', //dark
        features: ['bg', 'point', 'road'], // 设置地图显示要素 ['bg', 'road', 'building', 'point']
        defaultCursor: 'default'
      }
      const map = new AMap.Map('bigscreenWarnMapContainer', mapOptions)

      AMapRef.current = map
      _setMapCenter(regionCode)

      const loca = new window.Loca.Container({
        map
      })
      LocaRef.current = loca

      //为了弥补grey主题色的颜色不符合产品要求
      map.on('complete', () => {
        //启用地图范围限制
        const bounds = new AMap.Bounds(
          new AMap.LngLat(52.982575, 3.449744),
          new AMap.LngLat(160.358813, 57.048735)
        ) //西南角,东北角
        map.setLimitBounds(bounds) //getBounds：获取当前地图可视区域范围
        // console.log('触发地图资源加载完成事件');
        const mapContainerDom = document.getElementById(
          'bigscreenWarnMapContainer'
        )
        const amapLayersDom =
          mapContainerDom!.getElementsByClassName('amap-layers')[0]
        const apmapMaskDom = amapLayersDom.getElementsByClassName(
          'carorg-amap-zh-mask'
        )[0]
        if (!apmapMaskDom) {
          const zhDiv = document.createElement('div')
          zhDiv.classList.add('carorg-amap-zh-mask')
          amapLayersDom.prepend(zhDiv)
        }
      })
      map.on('click', () => {
        if (AlerInfoWindowRef.current) {
          AlerInfoWindowRef.current.close()
        }
      })

      //监听地图缩放,初始化不会执行
      map.on('zoomend', () => {
        const currZoom = map.getZoom()
        // console.log("--zoomend--触发地图缩放结束时的事件--currZoom--:", currZoom)
        if (!alerDataListRef.current.length) return
        if (mapShowTypeRef.current === 'poi') {
          _renderAlerClusterMaker(alerDataListRef.current, 'zoom')
        }
      })

      _getMapAlerData(key, 'initial')
    })

    return () => {
      _clearMapData()
      if (LocaRef.current) {
        LocaRef.current.destroy()
        LocaRef.current = null
      }
      if (AlerInfoWindowRef.current) {
        AlerInfoWindowRef.current.destroy()
      }

      if (AMapRef.current) {
        AMapRef.current.destroy()
        AMapRef.current = null
      }
    }
  }, [])

  return (
    <div className="warn-map-container" id="bigscreenWarnMapContainer"></div>
  )
})

export default AlerMap
